package me.zhengjie.service;

import me.zhengjie.exception.BlockChainBaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.web3j.crypto.*;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import me.zhengjie.utils.Convert;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class BlockChainService {

    /**
     * 根据用户私钥生成调用者信息
     * @param priKey
     * @return
     */
    public Credentials getCredentials(String priKey) {
        BigInteger bigInteger = new BigInteger(priKey, 16);
        ECKeyPair ecKeyPair = ECKeyPair.create(bigInteger);
        return Credentials.create(ecKeyPair);
    }

    /**
     * 获取交易gas价格
     * @param web3j
     * @return
     */
    public BigInteger getGasPrice(Web3j web3j) {
        try {
            EthGasPrice ethGasPrice = web3j.ethGasPrice().send();
            return ethGasPrice.getGasPrice();
        } catch (Exception e) {
            String message = "GasPrice 异常：" + e.getMessage();
            throw new BlockChainBaseException(message);
        }
    }

    /**
     * 获取原生币余额
     * @param web3j
     * @param address
     * @return
     */
    public BigDecimal getBalance(Web3j web3j, String address) {
        try {
            EthGetBalance ethGetBalance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
            return Convert.fromWei(ethGetBalance.getBalance().toString(), Convert.Unit.ETHER);
        } catch (Exception e) {
            String message = "获取 balance 异常：" + e.getMessage();
            throw new BlockChainBaseException(message);
        }
    }

    /**
     * 创建账户
     * @param walletFileBasePath
     * @param password
     * @return
     */
    public Map<String, Object> creatAccount(String walletFileBasePath, String password) {
        try {
            //生成12位助记词
            String mnemonic = MnemonicUtils.generateMnemonic(SecureRandom.getSeed(16));
            //使用助记词生成钱包种子
            byte[] seed = MnemonicUtils.generateSeed(mnemonic, null);
            int [] derivationPath = { 44 | Bip32ECKeyPair.HARDENED_BIT, 60 | Bip32ECKeyPair.HARDENED_BIT, Bip32ECKeyPair.HARDENED_BIT, 0 , 0 };
            Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed);
            Bip32ECKeyPair keyPair = Bip32ECKeyPair.deriveKeyPair(masterKeypair, derivationPath);
            // 生成 Keystore
            String walletFile = walletFile(keyPair, walletFileBasePath, password);
            //通过公钥生成钱包地址
            String address = Keys.getAddress(keyPair.getPublicKey());

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("address", "0x"+address);
            resultMap.put("privateKey", "0x"+keyPair.getPrivateKey().toString(16));
            resultMap.put("mnemonic", mnemonic);
            resultMap.put("walletFile", walletFile);
            return resultMap;
        } catch (Exception e) {
            log.error("blockChainService creatAccount error={}", e);
            String message = "blockChainService createAccount error! walletFileBasePath="+walletFileBasePath+", password="+password;
            throw new BlockChainBaseException(message);
        }
    }

    /**
     * 生成钱包地址
     * @param ecKeyPair
     * @param walletFilePath
     * @param password
     * @return
     * @throws CipherException
     * @throws IOException
     */
    private static String walletFile(ECKeyPair ecKeyPair, String walletFilePath, String password) throws CipherException, IOException {
        return WalletUtils.generateWalletFile(password, ecKeyPair, new File(walletFilePath), false);
    }

}
